package com.alinesno.cloud.initializr.starter.service.impl;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import javax.validation.constraints.NotNull;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alinesno.cloud.common.core.service.impl.IBaseServiceImpl;
import com.alinesno.cloud.initializr.starter.codegen.entity.GenTable;
import com.alinesno.cloud.initializr.starter.codegen.service.IGenTableService;
import com.alinesno.cloud.initializr.starter.common.impl.GenTableServiceImpl;
import com.alinesno.cloud.initializr.starter.common.mapper.GenTableColumnMapper;
import com.alinesno.cloud.initializr.starter.common.mapper.GenTableMapper;
import com.alinesno.cloud.initializr.starter.constants.DbType;
import com.alinesno.cloud.initializr.starter.dto.CheckDbConnectResult;
import com.alinesno.cloud.initializr.starter.dynamicSqlSession.SqlSessionFactoryUtil;
import com.alinesno.cloud.initializr.starter.entity.InitializrDbListEntity;
import com.alinesno.cloud.initializr.starter.repository.InitializrDbListMapper;
import com.alinesno.cloud.initializr.starter.service.IInitializrDbListService;

/**
 * 数据库管理Service业务层处理
 *
 * @author alinesno
 * @date 2021-05-10
 */
@Service
public class InitializrDbListServiceImpl extends IBaseServiceImpl<InitializrDbListEntity, InitializrDbListMapper>
		implements IInitializrDbListService {
	// 日志记录
	private static final Logger log = LoggerFactory.getLogger(InitializrDbListServiceImpl.class);

	@Autowired
	IGenTableService platformGenService;

	@Override
	public CheckDbConnectResult checkDbConnect(InitializrDbListEntity entity) {

		switch (entity.getDbType()) {
		case DbType.MY_SQL: {
			return checkMysqlConnect(entity);
		}
		default: {
			return new CheckDbConnectResult("不支持的数据库类型", "401", false);
		}
		}
	}

	/**
	 * 同步数据库
	 *
	 * @param id 配置 id
	 */
	@Override
	@Transactional
	public void syncDataBase(String id) {
		InitializrDbListEntity dbListEntity = findById(id);
		if (dbListEntity != null) {
			List<GenTable> oldTables = platformGenService.selectTablesByDbName(dbListEntity.getDbName());
			attachDb(dbListEntity, oldTables);
		}
	}

	/**
	 * 导入数据库表
	 *
	 * @param entity    数据库配置实体
	 * @param oldTables 旧的表集合,用于同步时恢复配置数据
	 */
	public void attachDb(InitializrDbListEntity entity, List<GenTable> oldTables) {
		SqlSession sqlSession = null;
		try {
			sqlSession = new SqlSessionFactoryUtil().creatSession(entity);
			GenTableServiceImpl thirdPartGenService = new GenTableServiceImpl();
			thirdPartGenService.setGenTableMapper(sqlSession.getMapper(GenTableMapper.class));
			thirdPartGenService.setGenTableColumnMapper(sqlSession.getMapper(GenTableColumnMapper.class));
			GenTable selectDb = new GenTable();
			selectDb.setTableSchema(entity.getDbName());
			List<GenTable> genTableList = thirdPartGenService.selectDbTableList(selectDb);

			platformGenService.delOldImport(entity);
			platformGenService.importGenTable(genTableList, entity, "robot");
			if (null != oldTables && !oldTables.isEmpty()) {
				GenTable old = oldTables.get(0);
				genTableList.forEach(genTable -> {
					genTable.setModuleName(old.getModuleName());
					genTable.setPackageName(old.getPackageName());
					platformGenService.updateMeta(genTable);
				});
			}
		} catch (Exception e) {
			deleteByIds(new String[] { entity.getId() });
			log.error("导入数据库失败", e);
			throw new IllegalArgumentException(e.getMessage());
		} finally {
			if (sqlSession != null) {
				sqlSession.close();
			}
		}
	}

	@Override
	public boolean save(InitializrDbListEntity entity) {
		boolean state = super.save(entity);
		if (state) {
			attachDb(entity, Collections.emptyList());
		}
		return state;
	}

	@Override
	public void deleteByIds(@NotNull String[] ids) {
		findByIds(Arrays.asList(ids)).forEach(dbListEntity -> platformGenService.delOldImport(dbListEntity));
		super.deleteByIds(ids);
	}

	private CheckDbConnectResult checkMysqlConnect(InitializrDbListEntity entity) {
		String url = String.format(
				"jdbc:mysql://%s:%s?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&serverTimezone=GMT",
				entity.getDbUrl(), entity.getDbPort());
		try {
			Connection connection = DriverManager.getConnection(
					StringEscapeUtils.escapeJava(StringEscapeUtils.unescapeHtml(url + "%2B8")),
					StringEscapeUtils.escapeJava(StringEscapeUtils.unescapeHtml(entity.getDbUsername())),
					StringEscapeUtils.escapeJava(StringEscapeUtils.unescapeHtml(entity.getDbPasswd())));
			connection.close();
		} catch (SQLException throwables) {
			return CheckDbConnectResult.reject("590");
		}
		return CheckDbConnectResult.accept("200");
	}
}
